/**
 * 
 */
package org.demetra.port;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;

import org.demetra.jets.bdb.OtpObjectBinding;

import com.ericsson.otp.erlang.OtpErlangAtom;
import com.ericsson.otp.erlang.OtpErlangDecodeException;
import com.ericsson.otp.erlang.OtpErlangList;
import com.ericsson.otp.erlang.OtpErlangObject;
import com.ericsson.otp.erlang.OtpErlangTuple;
import com.sleepycat.collections.StoredMap;
import com.sleepycat.db.Database;
import com.sleepycat.db.DatabaseConfig;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.DatabaseType;
import com.sleepycat.db.Environment;
import com.sleepycat.db.EnvironmentConfig;

/**
 * @author vvorobyov
 *
 */
public class BdbWorker extends WorkerBase {

	private static boolean create = true;
	private static final int EXIT_SUCCESS = 0;
	private static final int EXIT_FAILURE = 1;

	private Database db;
	private StoredMap map;
	private Environment env;
	
	/**
	 * @throws DatabaseException 
	 * @throws FileNotFoundException 
	 * 
	 */
	public BdbWorker(Environment env, String databaseName) 
	throws FileNotFoundException, DatabaseException {
		this.env = env;

		//
		// Lets mimic the db.AccessExample 100%
		// and use plain old byte arrays to store the key and data strings.
		//
		OtpObjectBinding keyBinding = new OtpObjectBinding();
		OtpObjectBinding dataBinding = new OtpObjectBinding();

		//
		// Open a data store.
		//
		DatabaseConfig dbConfig = new DatabaseConfig();
		if (create) {
			dbConfig.setAllowCreate(true);
			dbConfig.setType(DatabaseType.BTREE);
			dbConfig.setSortedDuplicates(true);
		}
		this.db = env.openDatabase(null, databaseName, null, dbConfig);

		//
		// Now create a collection style map view of the data store
		// so that it is easy to work with the data in the database.
		//
		this.map = new StoredMap(db, keyBinding, dataBinding, true);
	}

	/**
	 * @param args
	 * @throws FileNotFoundException 
	 */
	public static void main(String[] args) throws FileNotFoundException {
//		BdbWorker worker;
//		try {
//			worker = new BdbWorker(null, null);
//			worker.run();
//		} catch (DatabaseException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
		
		String clsName = BdbWorker.class.getSimpleName();
		System.setErr(new PrintStream(new FileOutputStream("c:/ZZZ.log"),true));
		System.err.println("ljhkl;jhkl;bk;lbk;j");
		boolean removeExistingDatabase = false;
		String databaseName = "access.db";

		try {

			EnvironmentConfig envConfig = new EnvironmentConfig();
			envConfig.setInitializeCache(true);
			envConfig.setInitializeLocking(true);
			if (create) {
				envConfig.setAllowCreate(true);
			}
			Environment env = new Environment(new File("."), envConfig);
			// Remove the previous database.
			if (removeExistingDatabase) {
				env.removeDatabase(null, databaseName, null);
			}

			// create the app and run it
			BdbWorker worker = new BdbWorker(env, databaseName);
			worker.run();
			
		} catch (DatabaseException e) {
			e.printStackTrace();
			System.exit(EXIT_FAILURE);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			System.exit(EXIT_FAILURE);
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(EXIT_FAILURE);
		}
		System.exit(EXIT_SUCCESS);
	}
	
	private static OtpErlangAtom ADD_OPCODE = new OtpErlangAtom("add");
	private static OtpErlangAtom GET_OPCODE = new OtpErlangAtom("get");
	private static OtpErlangAtom RET_OK = new OtpErlangAtom("ok");
	private static OtpErlangAtom RET_ERR = new OtpErlangAtom("error");

	@Override
	public void run() {
		try {
			while(true)
			{
				OtpErlangObject obj = receiveOtpObject();
				OtpErlangTuple reqTup = (OtpErlangTuple)obj;
				OtpErlangAtom opCode = (OtpErlangAtom) reqTup.elementAt(0);
				if(opCode.equals(ADD_OPCODE))
				{
					OtpErlangTuple kvTup = (OtpErlangTuple) reqTup.elementAt(1);
					map.put(kvTup.elementAt(0), kvTup.elementAt(1));
					sendOtpObject(RET_OK);
				}
				else if(opCode.equals(GET_OPCODE))
				{
					OtpErlangObject key = reqTup.elementAt(1);
					OtpErlangList resList = new OtpErlangList(
							(OtpErlangObject[])map.duplicates(key).toArray(
									new OtpErlangObject[0]));
					sendOtpObject(resList);
				}
				else
					sendOtpObject(RET_ERR);
					
			}
		} catch (OtpErlangDecodeException e) {
			e.printStackTrace();
			System.exit(EXIT_FAILURE);
		} catch (IOException e) {
			e.printStackTrace();
			System.exit(EXIT_FAILURE);
		}
	}
//	@Override
//	public void run() {
//		try {
//			while(true)
//			{
//				sendOtpObject(receiveOtpObject());				
//			}
//		} catch (OtpErlangDecodeException e) {
//			e.printStackTrace();
//			System.exit(EXIT_FAILURE);
//		} catch (IOException e) {
//			e.printStackTrace();
//			System.exit(EXIT_FAILURE);
//		}
//	}

}
